package newcrunch.typography;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import newcrunch.util.PropertyLoader;

/**
 * Stores the main table and the dialogs to display the details
 * 
 * Steps to add a new aspect:
 * 1. Add the desired row to the TypoMainTableModel
 * 2. Add a public static final int variable to store the aspect's row
 * 3. Add the dialog creation code in createDialogs()
 * 4. Add the code to populate the dialog in JavaAnalyzer's analyze method
 * 5. Add the standard to the property file and update the JavaStandards class accordingly
 * 
 * @author WL
 */
public class TypoMainTable extends JTable
{
    private static Color color1 = new Color(237, 243, 254);
    private static Color color2 = Color.WHITE;
    public static int[] subheadingRows = { 0, 21, 30, 37 };
    
    private JComboBox comboBox = new JComboBox(JavaStandards.getComments());
    
    //column position
    public static final int RESULTS_COLUMN = 1;
    public static final int SD_COLUMN = 2;
    public static final int STANDARDS_COLUMN = 3;
    public static final int COMMENTS_COLUMN = 4;
    
    //stores the row positions where the results are displayed
    public static final int SPACES_AFTER = 1;
    public static final int SPACES_AFTER_SPEC = 2;
    public static final int SPACES_AFTER_COMMA = 8;
    public static final int SPACES_AFTER_SEMIFOR = 10;
    public static final int SPACES_AFTER_LPAREN = 14;
    public static final int SPACES_AFTER_LBRACKET = 16;
    public static final int SPACES_AFTER_LANGULAR = 18;
    public static final int SPACES_AFTER_CAST = 13;
    
    public static final int SPACES_BEFORE_COLON = 6;
    public static final int SPACES_BEFORE_COMMA = 7;
    public static final int SPACES_BEFORE_SEMI = 9;
    public static final int SPACES_BEFORE_LPAREN = 11;
    public static final int SPACES_BEFORE_RPAREN = 15;
    public static final int SPACES_BEFORE_RBRACKET = 17;
    public static final int SPACES_BEFORE_RANGULAR = 19;
    
    public static final int SPACES_BEFORE_AFTER_BIN = 3;
    public static final int SPACES_BEFORE_AFTER_DOT = 4;
    public static final int SPACES_BEFORE_AFTER_COLON = 5;
    
    public static final int UNARY_OPERATORS = 12;
    public static final int SINGLE_VARIABLES = 31;
    public static final int VARIABLE_NAME = 32;
    public static final int CONSTANT_NAME = 33;
    public static final int METHOD_NAME = 34;
    public static final int CLASS_INTERFACE_NAME = 35;
    
    public static final int AFTER_HEADER = 22;
    public static final int BTW_CLASSES = 23;
    public static final int BTW_METHODS = 24;
    public static final int BEFORE_COMMENTS = 25;
    public static final int BTW_FIELDS_METHOD = 26;
    
    public static final int BLANKS = 27;
    public static final int COMMENTS = 28;
    
    public static final int STMT_PER_LINE = 38;
    
    public static final int CONSTRUCTOR_COUNT = 39;
    
    public static final int AVG_LEN_METHOD = 40;
    public static final int AVG_LEN_CLASS = 41;
    
    public static final int LONGEST_LEN = 42;
    
    public static final int BRACE_STYLE = 43;
    
    //use the row positions as mappings to the dialogs to display
    //when the mouse clicks on that row in the tabs
    private HashMap<Integer, TypoDetailsDialog> dialogs = new HashMap<Integer, TypoDetailsDialog>();
    
    public static String[] spacesHeaders = { "Keyword", "Line", "Column", "Spaces" };
    public static String[] beforeAfterHeaders = { "Keyword", "Line", "Column", "Spaces Before", "Spaces After" };
    public static String[] nameHeaders = { "Name", "Line", "Column", "Style" };
    public static String[] singleIdentifierHeaders = { "Name", "Line", "Column" };
    public static String[] avgLengthHeaders = { "Name", "Line", "Length" };
    public static String[] longestLengthHeaders = { "Line", "Length" };
    public static String[] blanksCommentsHeaders = { "Line" };
    public static String[] stmtsPerLineHeaders = { "Line", "Number of Statements" };
    public static String[] braceStyleHeaders = { "Line", "Brace Style" };
    public static String[] blanksHeaders = { "Line", "Blank Lines" };
    
    static
    {
        color1 = PropertyLoader.getColorProperty("color1");
        color2 = PropertyLoader.getColorProperty("color2");
    }
    
    public TypoMainTable()
    {
        super();
        
        initComponents();
        
        createDialogs();
        
        comboBox.setEditable(true);
        
        addMouseListener(new MouseAdapter(){
            @Override
            public void mouseClicked(MouseEvent evt)
            {
                TypoDetailsDialog selectedDialog = null;
                if (getSelectedColumn() == 0 &&
                        (selectedDialog = dialogs.get(getSelectedRow())) != null)
                        selectedDialog.setVisible(true);
            }
        });
        
    }
    
    public void hideAllDialogs()
    {
        for (TypoDetailsDialog dialog : dialogs.values())
            if (dialog.isVisible())
                dialog.setVisible(false);
    }
    
    public void initComponents()
    {
        this.setFont(new java.awt.Font("Verdana", 0, 14)); // NOI18N
        this.setModel(new TypoMainTableModel());
        
        this.setRowHeight(25);
        this.setShowHorizontalLines(false);
        this.getTableHeader().setReorderingAllowed(false);
        this.getColumnModel().getColumn(0).setMinWidth(490);
        this.getColumnModel().getColumn(0).setPreferredWidth(490);
        this.getColumnModel().getColumn(TypoMainTable.COMMENTS_COLUMN).setCellEditor(new DefaultCellEditor(comboBox));
//        this.getColumnModel().getColumn(TypoMainTable.STANDARDS_COLUMN).setCellRenderer(new javax.swing.table.DefaultTableCellRenderer());
    }
    
    public void loadStandards()
    {
        for (int i = 0; i < JavaStandards.length(); i++)
            setValueAt(JavaStandards.getProperty(i), i, TypoMainTable.STANDARDS_COLUMN);
    }
    
    /**
     * Gets the dialog that corresponds to the particular row.
     * @param row
     * @return 
     */
    public TypoDetailsDialog getDialog(int row)
    {
        return dialogs.get(row);
    }
    
    public void createDialogs()
    {
        dialogs.put(SPACES_AFTER , new TypoDetailsDialog("Spaces after keywords", spacesHeaders));
        dialogs.put(SPACES_AFTER_SPEC , new TypoDetailsDialog("Spaces after super, this, default", spacesHeaders));
        dialogs.put(SPACES_AFTER_COMMA , new TypoDetailsDialog("Spaces after ,", spacesHeaders));
        dialogs.put(SPACES_AFTER_SEMIFOR , new TypoDetailsDialog("Spaces after ; in for loops", spacesHeaders));
        dialogs.put(SPACES_AFTER_LPAREN , new TypoDetailsDialog("Spaces after (", spacesHeaders));
        dialogs.put(SPACES_AFTER_LBRACKET , new TypoDetailsDialog("Spaces after [", spacesHeaders));
        dialogs.put(SPACES_AFTER_LANGULAR , new TypoDetailsDialog("Spaces after <", spacesHeaders));
        dialogs.put(SPACES_BEFORE_COLON , new TypoDetailsDialog("Spaces before : in switch statements", spacesHeaders));
        dialogs.put(SPACES_BEFORE_COMMA , new TypoDetailsDialog("Spaces before ,", spacesHeaders));
        dialogs.put(SPACES_BEFORE_SEMI , new TypoDetailsDialog("Spaces before ;", spacesHeaders));
        dialogs.put(SPACES_BEFORE_LPAREN , new TypoDetailsDialog("Spaces between method name and (", spacesHeaders));
        dialogs.put(SPACES_BEFORE_RPAREN , new TypoDetailsDialog("Spaces before )", spacesHeaders));
        dialogs.put(SPACES_BEFORE_RBRACKET , new TypoDetailsDialog("Spaces before ]", spacesHeaders));
        dialogs.put(SPACES_BEFORE_RANGULAR , new TypoDetailsDialog("Spaces before >", spacesHeaders));
        
        dialogs.put(SPACES_BEFORE_AFTER_BIN , new TypoDetailsDialog("Spaces before and after binary operators", beforeAfterHeaders));
        dialogs.put(SPACES_BEFORE_AFTER_DOT , new TypoDetailsDialog("Spaces before and after .", beforeAfterHeaders));
        dialogs.put(SPACES_BEFORE_AFTER_COLON , new TypoDetailsDialog("Spaces before and after :", beforeAfterHeaders));
        
        dialogs.put(UNARY_OPERATORS, new TypoDetailsDialog("Spaces after prefix and before postfix unary operators", 
                            spacesHeaders));
        
        dialogs.put(SPACES_AFTER_CAST, new TypoDetailsDialog("Spaces after ) in a cast expression", 
                            spacesHeaders));
        
        dialogs.put(SINGLE_VARIABLES, new TypoDetailsDialog("Single character variables", singleIdentifierHeaders));
        dialogs.put(VARIABLE_NAME, new TypoDetailsDialog("Variable naming", nameHeaders));
        dialogs.put(METHOD_NAME, new TypoDetailsDialog("Method naming", nameHeaders));
        dialogs.put(CONSTANT_NAME, new TypoDetailsDialog("Method naming", nameHeaders));
        dialogs.put(CLASS_INTERFACE_NAME, new TypoDetailsDialog("Class / Interface naming", nameHeaders));
        
        dialogs.put(AVG_LEN_METHOD, new TypoDetailsDialog("Average method length", avgLengthHeaders));
        dialogs.put(AVG_LEN_CLASS, new TypoDetailsDialog("Average class length", avgLengthHeaders));
        
        dialogs.put(LONGEST_LEN, new TypoDetailsDialog("Lines that exceed the given length", 
                longestLengthHeaders));
        
        dialogs.put(BLANKS, new TypoDetailsDialog("Location of blank lines", 
                blanksCommentsHeaders));
        
        dialogs.put(COMMENTS, new TypoDetailsDialog("Location of lines containing comments", 
                blanksCommentsHeaders));
        
        //stmtsPerLineHeaders
        dialogs.put(STMT_PER_LINE, new TypoDetailsDialog("Statements per line", 
                stmtsPerLineHeaders));
        
        dialogs.put(BRACE_STYLE, new TypoDetailsDialog("Brace Styles", 
                braceStyleHeaders));
        
        //blank lines
        dialogs.put(AFTER_HEADER, new TypoDetailsDialog("After package and import declaration section", 
                blanksHeaders));
        dialogs.put(BTW_CLASSES, new TypoDetailsDialog("Between classes", 
                blanksHeaders));
        dialogs.put(BTW_METHODS, new TypoDetailsDialog("Between methods", 
                blanksHeaders));
        dialogs.put(BEFORE_COMMENTS, new TypoDetailsDialog("Before block or single-line comments", 
                blanksHeaders));
        dialogs.put(BTW_FIELDS_METHOD, new TypoDetailsDialog("Between last field declaration and first method declaration", 
                blanksHeaders));
        
        dialogs.put(CONSTRUCTOR_COUNT, new TypoDetailsDialog("Constructor locations", blanksCommentsHeaders));
    }
    
    @Override
    public TableCellRenderer getCellRenderer(int row, int column) 
    {
        DefaultTableCellRenderer result = new DefaultTableCellRenderer()
        {
            public Component getTableCellRendererComponent(JTable table, Object value, 
                    boolean isSelected, boolean hasFocus, int row, int column) 
            {
                Component result = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                
                //format the header rows
                for (int r : subheadingRows)
                {
                    if (row == r)
                    {
                        Font font = result.getFont();
                        result.setFont(font.deriveFont(Font.BOLD));    
                        break;
                    }
                }
                
                return result;
            }
        };
        
        //for aligning the result display
        if (column > 0)
            result.setHorizontalAlignment(SwingConstants.CENTER);
        
        //for row striping
        if (row % 2 == 0)
            result.setBackground(color1);
        else
            result.setBackground(color2);
        
        return result;
    }
}
